/**
 * Axios拦截器配置文件
 * 
 * 本文件配置了Axios的请求和响应拦截器，用于处理HTTP请求的公共逻辑，如：
 * 1. 添加认证令牌到请求头
 * 2. 统一处理响应错误
 * 3. 处理特定业务逻辑，如令牌过期的自动登出
 * 
 * 新手须知：
 * 拦截器是一种AOP(面向切面编程)的实现，可以在请求发送前和响应接收后统一处理某些逻辑，
 * 避免在每个API调用处重复编写相同的代码，提高代码复用性和可维护性。
 */

// 导入用户状态管理store，用于处理登出逻辑
import { useUserStore } from '@/store'
// 导入获取令牌的工具函数
import { getToken } from '@/utils/auth'
// 导入ArcoDesign组件库中的消息提示和模态框组件
import { Message, Modal } from '@arco-design/web-vue'
// 导入axios HTTP客户端库
import axios from 'axios'

/**
 * HTTP响应数据接口
 * 
 * 定义了后端API返回的统一数据结构
 * 使用泛型T来表示具体的业务数据类型，提高类型安全性
 */
export interface HttpResponse<T = unknown> {
  // HTTP状态码
  status: number
  // 消息描述
  msg: string
  // 业务状态码，用于前端判断业务处理结果
  code: number
  // 实际业务数据，类型由泛型T决定
  data: T
}

/**
 * 配置Axios的基础URL
 * 
 * 从环境变量中读取API基础URL，实现开发和生产环境的配置分离
 * Vite会自动加载.env文件中的环境变量，前缀为VITE_的变量可在客户端代码中访问
 */
if (import.meta.env.VITE_API_BASE_URL) {
  axios.defaults.baseURL = import.meta.env.VITE_API_BASE_URL
}

/**
 * 请求拦截器
 * 
 * 在发送请求前执行的逻辑，主要用于添加认证信息、请求参数处理等
 * 
 * 最佳实践：
 * 1. 将认证逻辑集中在拦截器中，避免在每个请求中手动添加
 * 2. 使用Bearer Token认证方式，符合OAuth 2.0规范
 */
axios.interceptors.request.use(
  // 请求成功拦截函数
  (config: any) => {
    // 获取存储的认证令牌
    const token = getToken()
    // 如果令牌存在，则添加到请求头中
    if (token) {
      // 确保headers对象存在
      if (!config.headers) {
        config.headers = {}
      }
      // 添加Authorization请求头，使用Bearer Token认证方式
      // Bearer是OAuth 2.0的标准认证方式，表示请求携带的是访问令牌
      config.headers.Authorization = `Bearer ${token}`
    }
    // 返回修改后的配置，继续发送请求
    return config
  },
  // 请求错误拦截函数
  (error) => {
    // 请求配置阶段发生错误时的处理
    // 返回一个被拒绝的Promise，可以在调用处捕获这个错误
    return Promise.reject(error)
  }
)

/**
 * 响应拦截器
 * 
 * 在接收到响应后执行的逻辑，主要用于统一处理响应数据、错误处理等
 * 
 * 最佳实践：
 * 1. 统一处理业务错误码，减少重复代码
 * 2. 特殊错误码单独处理，如令牌相关错误自动跳转登录页
 * 3. 使用统一的消息提示组件，保持用户界面风格一致
 */
axios.interceptors.response.use(
  // 响应成功拦截函数
  (response: any) => {
    console.log('拦截器拦截响应内容....')
    // 获取响应中的数据部分
    const res = response.data
    
    // 判断业务状态码，非20000表示业务处理出错
    // 注意：这里的状态码是自定义的业务状态码，不是HTTP状态码
    if (res.code !== 20000) {
      // 显示错误消息提示
      Message.error({
        content: res.msg || 'Error', // 优先使用后端返回的错误信息
        duration: 5 * 1000, // 显示5秒
      })
      
      // 特殊错误码处理：令牌相关错误
      // 50008: 非法令牌; 50012: 其他客户端登录; 50014: 令牌过期
      if ([50008, 50012, 50014].includes(res.code) && response.config.url !== '/api/user/info') {
        // 显示登出确认对话框
        Modal.error({
          title: 'Confirm logout',
          content: 'You have been logged out, you can cancel to stay on this page, or log in again',
          okText: 'Re-Login',
          // 点击确认按钮的回调函数
          async onOk() {
            // 获取用户状态管理store
            const userStore = useUserStore()
            // 执行登出操作
            await userStore.logout()
            // 刷新页面，重新加载应用
            window.location.reload()
          },
        })
      }
      
      // 返回一个被拒绝的Promise，这样API调用处可以通过catch捕获这个错误
      return Promise.reject(new Error(res.msg || 'Error'))
    }
    
    // 业务处理成功，返回响应数据
    // 注意这里直接返回res而不是response，简化了API调用处的数据获取
    return res
  },
  // 响应错误拦截函数
  (error) => {
    // 显示错误消息提示
    Message.error({
      content: error.msg || 'Request Error', // 优先使用错误对象中的消息
      duration: 5 * 1000, // 显示5秒
    })
    // 返回一个被拒绝的Promise，这样API调用处可以通过catch捕获这个错误
    return Promise.reject(error)
  }
)
